/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.editpart;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Iterator;

import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.NodeEditPart;
import org.eclipse.ui.views.properties.IPropertySource;
import org.eclipse.uml2.uml.ElementImport;

import com.cea.papyrus.core.directedit.LabelDirectEditPolicy;
import com.cea.papyrus.core.editor.ModelManager;
import com.cea.papyrus.core.editpart.connection.AnchorableGraphNodeEditPart;
import com.cea.papyrus.core.figures.ElementFigure;
import com.cea.papyrus.core.figures.IconFigure;
import com.cea.papyrus.core.helper.ModelerHelper;
import com.cea.papyrus.core.listener.GraphElementListener;
import com.cea.papyrus.core.ui.properties.advanced.EObjectPropertySource;
import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.diagraminterchange2.di2.Di2Package;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;
import com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge;

// TODO: Auto-generated Javadoc
/**
 * The Class GraphNodeEditPart.
 */
public class GraphNodeEditPart 	extends AnchorableGraphNodeEditPart
implements NodeEditPart, PropertyChangeListener, IUMLObjectEditPart
{
	
	/** The anchor. */
	protected ConnectionAnchor anchor;
	
	/** The graph element listener. */
	protected  GraphElementListener graphElementListener;
	
	/** The property source. */
	protected IPropertySource propertySource = null;
	
	/** The target. */
	protected Notifier target;
	
	/** The channel. */
	protected static final int channel =7;
	
	/** The model manager. */
	protected ModelManager modelManager;

	/**
	 * Creates a new NodeEditPart instance.
	 * All element that can be display is a graphNode.
	 * 
	 * @param modelManager the model manager
	 * @param graphnode the graphnode
	 * @param graphNode 	 */
	public GraphNodeEditPart(GraphNode graphnode, ModelManager modelManager){
		this.modelManager=modelManager;
		this.setModel(graphnode);
		this.graphElementListener= new GraphElementListener(this);
	}


	/**
	 * when the mole is changed.
	 * 
	 * @param notification the notification
	 */
	public void notifyChanged(Notification notification) {
		super.notifyChanged(notification);
		int featureId = notification.getFeatureID( Di2Package.class );
		// we have to do refesh and not refreshvisual 
		this.refresh();
		
		
		int type = notification.getEventType();
		if((type==Notification.SET)||(type==Notification.ADD)){
			modelManager.modifGraphElement(this.getGraphNode());
		}
	}

	/**
	 * return if the Edit part is visible.
	 * 
	 * @return true, if is visible
	 */

	public boolean isVisible() {
		return this.getGraphNode().isIsVisible();
	}
	
	/**
	 * Sets the visible.
	 * 
	 * @param b the b
	 */
	public void setVisible(boolean b) {
		this.getGraphNode().setIsVisible(b);
	}

	/* (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractEditPart#createEditPolicies()
	 */
	/**
	 * Creates the edit policies.
	 */
	@Override
	protected void createEditPolicies() {
		super.createEditPolicies();
		//manage suppression of this element
		this.installEditPolicy( EditPolicy.COMPONENT_ROLE, new GraphNodeWithSemanticEditPolicy(null) );
		
		this.installEditPolicy(DimensionAdaptationEditPolicy.DIMENSION_ADAPTATION, new DimensionAdaptationEditPolicy());
		this.installEditPolicy( EditPolicy.DIRECT_EDIT_ROLE, new LabelDirectEditPolicy() );
		//manage connection between this element
		this.installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new GraphNodeEditPolicy() );
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.IActionFilter#testAttribute()
	 */
	/**
	 * Test attribute.
	 * 
	 * @param value the value
	 * @param target the target
	 * @param name the name
	 * 
	 * @return true, if test attribute
	 */
	public boolean testAttribute(Object target, String name, String value) {

		if (target instanceof IUMLObjectEditPart) {			
			return IUMLObjectEditPart.umlFilter.testAttribute(target, name, value);
		}

		return false;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.editpart.IUMLElementEditPart#getUmlElement()
	 */
	/**
	 * Checks if is element import.
	 * 
	 * @return true, if is element import
	 */
	public boolean isElementImport() {
		if (this.getGraphNode().getSemanticModel()==null) {
			return false;
		}
		return  (((Uml1SemanticModelBridge)this.getGraphNode().getSemanticModel()).getElement() instanceof ElementImport);

	}
	/*
	 * (non-Javadoc)
	 * @see com.cea.papyrus.core.common.editpart.IUMLElementEditPart#getElementImport()
	 */
	/**
	 * Gets the element import.
	 * 
	 * @return the element import
	 */
	public ElementImport getElementImport(){
		if (this.getGraphNode().getSemanticModel()==null) {
			return null;
		}
		if (((Uml1SemanticModelBridge)this.getGraphNode().getSemanticModel()).getElement() instanceof ElementImport){
			return (ElementImport)((Uml1SemanticModelBridge)this.getGraphNode().getSemanticModel()).getElement();
		}
		return null;	
	}


	/* (non-Javadoc)
	 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
	 */
	/**
	 * Property change.
	 * 
	 * @param evt the evt
	 */
	public void propertyChange(PropertyChangeEvent evt) {
		Debug.debug(this,"+-------------> evt GraphNodeEditPart "+evt, this.channel);
		this.refresh();
	}

	
	
	
	/* (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractEditPart#refreshVisuals()
	 */
	/**
	 * Refresh visuals.
	 */
	@Override
	protected void refreshVisuals() {

		Dimension size = this.getGraphNode().getSize();
		Point p = this.getGraphNode().getPosition();
		Rectangle r = new Rectangle(p ,size);
		String name="This GraphNode is not associated to an Uml Element";

		ElementFigure f = (ElementFigure)this.getFigure();
		f.setName(name);

		((GraphicalEditPart) this.getParent()).setLayoutConstraint(
				this,
				f,
				r);
	}

	/**
	 * Activates this EditPart, which in turn activates
	 * its children and EditPolicies. Subclasses should <em>extend</em> this method to add
	 * listeners to the model. Activation indicates that the EditPart is realized in an
	 * EditPartViewer. <code>deactivate()</code> is the inverse, and is eventually called on
	 * all EditParts.
	 * @see EditPart#activate()
	 * @see #deactivate()
	 */
	@Override
	public void activate()
	{
		if (this.isActive()) {
			return;
		}
		super.activate();
		// start listening for changes in the model
		((Notifier)this.getGraphNode()).eAdapters().add(graphElementListener);
		Iterator propertiesIterator= this.getGraphNode().getProperty().iterator();
		while(propertiesIterator.hasNext()){
			((Notifier)propertiesIterator.next()).eAdapters().add(graphElementListener);
		}	
	}

	/* (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#deactivate()
	 */
	/**
	 * Deactivate.
	 */
	@Override
	public void deactivate()
	{
		if (!this.isActive()) {
			return;
		}

		// stop listening for changes in the model
		((Notifier)this.getGraphNode()).eAdapters().remove(graphElementListener);
		Iterator propertiesIterator= this.getGraphNode().getProperty().iterator();
		while(propertiesIterator.hasNext()){
			((Notifier)propertiesIterator.next()).eAdapters().remove(graphElementListener);
		}
		super.deactivate();


	}


	/* (non-Javadoc)
	 * @see org.eclipse.emf.common.notify.Adapter#getTarget()
	 */
	/**
	 * Gets the target.
	 * 
	 * @return the target
	 */
	public Notifier getTarget() {
		return this.target;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.emf.common.notify.Adapter#isAdapterForType(java.lang.Object)
	 */
	/**
	 * Checks if is adapter for type.
	 * 
	 * @param type the type
	 * 
	 * @return true, if is adapter for type
	 */
	public boolean isAdapterForType(Object type) {
		return type.equals( this.getModel().getClass() );
	}


	/* (non-Javadoc)
	 * @see org.eclipse.emf.common.notify.Adapter#setTarget(org.eclipse.emf.common.notify.Notifier)
	 */
	/**
	 * Sets the target.
	 * 
	 * @param newTarget the new target
	 */
	public void setTarget(Notifier newTarget) {
		this.target = newTarget;
	}


	/* (non-Javadoc)
	 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
	 */
	/**
	 * Gets the adapter.
	 * 
	 * @param key the key
	 * 
	 * @return the adapter
	 */
	@Override
	public Object getAdapter(Class key) {
		if (IPropertySource.class == key) {
			return this.getPropertySource();
		}

		return super.getAdapter( key );
	}

	

	/* (non-Javadoc)
	 * @see com.ibm.itso.sal330r.gefdemo.edit.NetworkElementEditPart#getPropertySource()
	 */
	/**
	 * Gets the property source.
	 * 
	 * @return the property source
	 */
	protected IPropertySource getPropertySource() {
		if( this.propertySource == null ) {
			this.propertySource = new EObjectPropertySource( this.getGraphNode() );
		}
		return this.propertySource;

	}

	/* (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#createFigure()
	 */
	/**
	 * Creates the figure.
	 * 
	 * @return the I figure
	 */
	@Override
	protected IFigure createFigure() {

		ElementFigure figure = new ElementFigure();
		return figure;

	}

	/* (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getFigure()
	 */
	@Override
	public IFigure getFigure() {
		// overrides for visibility
		return super.getFigure();
	}
	

	/**
	 * Change figure to stereotype figure.
	 */
	public void changeFigureToStereotypeFigure() {
		if ( ((figure instanceof IconFigure)
		    && !getGraphNode().getSemanticModel().getPresentation().equals(ModelerHelper.IMAGE_STEREOTYPE_PRESENTATION))
			|| ((!(figure instanceof IconFigure)) 
			&& getGraphNode().getSemanticModel().getPresentation().equals(ModelerHelper.IMAGE_STEREOTYPE_PRESENTATION))) {
			
			changeEditPartFigure();		
		}
	}
	

	/**
	 * Change edit part figure.
	 */
	public void changeEditPartFigure(){
		IFigure fparent = figure.getParent();
		if (fparent != null) {	
			// Initialize children list to force refresh on children editparts
			for (int i = 0; i < getChildren().size(); i++) {
				EditPart ep = (EditPart)getChildren().get(i);
				removeChild(ep);
			}
			
			// Unselect editpart
			setFocus(false);
			setSelected(EditPart.SELECTED_NONE);
					
			// Unregister current figure
			unregisterVisuals();
			
			// Create new figure
			IFigure newFigure = createFigure();
			
			// Remove current figure and add new one in the figure tree
			fparent.remove(figure);
			fparent.add(newFigure);
			
			// Set figure and register it
			setFigure(newFigure);		
			registerVisuals();

			children = new ArrayList();	
			
			// Install action handle
			installActionHandle();
			
			// Refresh editpart
			refresh();
		}
	}
	
	/**
	 * Install Action handles for this editPart. Use same toolEntries than in
	 * palette
	 */
	protected void installActionHandle() {}


	/**
	 * Gets the model manager.
	 * 
	 * @return the model manager of the edit part
	 */
	public ModelManager getModelManager() {
		return modelManager;
	}

	/**
	 * Always return true unless you know what you do.
	 * This method is used in {@link com.cea.papyrus.core.editpart.LayoutEditPolicy} in order to
	 * know how to compute the coordinate of a added part.
	 * @TODO move this method to more appropriate place. 
	 * @return
	 */
	public boolean needRelativeTranslationForAddCommand()
	{
	    return true;
	}
	
}